home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 090 / byte0387.arc / SEEILBM.C < prev    next >
Encoding:
C/C++ Source or Header  |  1980-01-01  |  20.8 KB  |  640 lines

  1.  /*****************************************************************
  2.  *
  3.  * SeeILBM.c
  4.  *   Read an ILBM file and display as a screen/window until closed.
  5.  *   Simulated close gadget in upper left corner of window.
  6.  *   Clicking below title bar area toggles screen bar for dragging.
  7.  *
  8.  *  By Carolyn Scheppner   CBM  03/15/86
  9.  *  Modified 09/02/86 - Only global frame is iFrame
  10.  *                      Use message->MouseX and Y
  11.  *                      Wait() for IDCMP
  12.  *
  13.  * Based on early ShowILBM.c    11/12/85
  14.  *  By Jerry Morrison, Steve Shaw, and Steve Hayes, Electronic Arts.
  15.  *  This software is in the public domain.
  16.  *
  17.  * >>NOTE<<: This example must be linked with additional IFF rtn files.
  18.  *           See linkage information below.
  19.  *
  20.  * The IFF reader portion is essentially a recursive-descent parser.
  21.  * This program will look into a CAT or LIST to find a FORM ILBM, but it
  22.  * won't look inside another FORM type for a nested FORM ILBM.
  23.  *
  24.  * The display portion is specific to the Commodore Amiga computer.
  25.  *
  26.  * Linkage Information:
  27.  *
  28.  * FROM     LStartup.obj, SeeILBM.o, iffr.o, ilbmr.o, unpacker.o
  29.  * TO       SeeILBM
  30.  * LIBRARY  LC.lib, Amiga.lib
  31.  * 
  32.  **************************************************************************/
  33.  
  34. #include <exec/types.h>
  35. #include <exec/memory.h>
  36. #include <libraries/dos.h>
  37. #include <graphics/gfxbase.h>
  38. #include <graphics/rastport.h>
  39. #include <graphics/gfx.h>
  40. #include <graphics/view.h>
  41. #include <workbench/startup.h>
  42. #include <intuition/intuition.h>
  43. #include <lattice/stdio.h>
  44.  
  45. #include "iff/ilbm.h"
  46.  
  47. /* This example's max number of planes in a bitmap. Could use MaxAmDepth. */
  48. #define EXDepth 5
  49. #define maxColorReg (1<<EXDepth)
  50. #define MIN(a,b) ((a)<(b)?(a):(b))
  51.  
  52. #define SafeFreeMem(p,q) {if(p)FreeMem(p,q);}
  53.     
  54. /* Define the size of a temp buffer used in unscrambling the ILBM rows.*/
  55. #define bufSz 512
  56.  
  57. /* general usage pointers */
  58. struct GfxBase       *GfxBase;
  59. struct IntuitionBase *IntuitionBase;
  60. struct IntuiMessage  *message;
  61.  
  62. /* Globals for displaying an image */
  63. struct Screen   *screen1;
  64. struct Window   *window1;
  65. struct RastPort *rport1;
  66. struct ViewPort *vport1;
  67.  
  68. struct BitMap   tBitMap;      /* Temp BitMap struct for small pics  */
  69.  
  70. /* For WorkBench startup */    
  71. extern struct WBStartup *WBenchMsg;
  72. BOOL   fromWB;
  73. struct FileLock *startLock, *newLock;
  74.  
  75. /* Other globals */
  76. int   i, error;
  77. BYTE  c;
  78. BOOL  TBtoggle, Done;
  79. ULONG class, code, pBytes;
  80. SHORT mouseX, mouseY;
  81.  
  82. /* Structures for new Screen, new Window */
  83.  
  84. struct   TextAttr       TextFont = {
  85.    "topaz.font",                    /* Font Name   */
  86.    TOPAZ_EIGHTY,                    /* Font Height */
  87.    FS_NORMAL,                       /* Style       */
  88.    FPF_ROMFONT,                     /* Preferences */
  89.    };
  90.  
  91. struct   NewScreen      ns = {
  92.    0, 0,                                  /* LeftEdge and TopEdge   */
  93.    0, 0,                                  /* Width and Height       */
  94.    0,                                     /* Depth                  */
  95.    -1, -1,                                /* DetailPen and BlockPen */
  96.    NULL,                                  /* Special display modes  */
  97.    CUSTOMSCREEN,                          /* Screen Type            */
  98.    &TextFont,                             /* Use my font            */
  99.    NULL,                                  /* Title                  */
  100.    NULL,                                  /* No gadgets yet         */
  101.    NULL,                                  /* Ptr to CustomBitmap    */
  102.    };
  103.  
  104. struct   NewWindow      nw = {
  105.    0, 0,                                  /* LeftEdge and TopEdge */
  106.    0, 0,                                  /* Width and Height */
  107.    -1, -1,                                /* DetailPen and BlockPen */
  108.    MOUSEBUTTONS,                          /* IDCMP Flags */
  109.    ACTIVATE
  110.    |BACKDROP
  111.    |BORDERLESS,                           /* Flags */
  112.    NULL, NULL,                            /* Gadget and Image pointers */
  113.    NULL,                                  /* Title string */
  114.    NULL,                                  /* Put Screen ptr here */
  115.    NULL,                                  /* SuperBitMap pointer */
  116.    0, 0,                                  /* MinWidth and MinHeight */
  117.    0, 0,                                  /* MaxWidth and MaxHeight */
  118.    CUSTOMSCREEN,                          /* Type of window */
  119.    };
  120.  
  121. USHORT  allBgColor[32];
  122.  
  123.  
  124. /* Message strings for IFFP codes. */
  125. char MsgOkay[]        = {"(IFF_OKAY) No FORM ILBM in the file." };
  126. char MsgEndMark[]     = {"(END_MARK) How did you get this message?" };
  127. char MsgDone[]        = {"(IFF_DONE) All done."};
  128. char MsgDos[]         = {"(DOS_ERROR) The DOS returned an error." };
  129. char MsgNot[]         = {"(NOT_IFF) Not an IFF file." };
  130. char MsgNoFile[]      = {"(NO_FILE) No such file found." };
  131. char MsgClientError[] = {"(CLIENT_ERROR) ShowILBM bug or insufficient RAM."};
  132. char MsgForm[]        = {"(BAD_FORM) A malformed FORM ILBM." };
  133. char MsgShort[]       = {"(SHORT_CHUNK) A malformed FORM ILBM." };
  134. char MsgBad[]         = {"(BAD_IFF) A mangled IFF file." };
  135.  
  136. /* THESE MUST APPEAR IN RIGHT ORDER!! */
  137. char *IFFPMessages[-LAST_ERROR+1] = {
  138.     /*IFF_OKAY*/  MsgOkay,
  139.     /*END_MARK*/  MsgEndMark,
  140.     /*IFF_DONE*/  MsgDone,
  141.     /*DOS_ERROR*/ MsgDos,
  142.     /*NOT_IFF*/   MsgNot,
  143.     /*NO_FILE*/   MsgNoFile,
  144.     /*CLIENT_ERROR*/ MsgClientError,
  145.     /*BAD_FORM*/  MsgForm,
  146.     /*SHORT_CHUNK*/  MsgShort,
  147.     /*BAD_IFF*/   MsgBad
  148.     };
  149.  
  150. /*------------ ILBM reader -----------------------------------------------*/
  151. /* ILBMFrame is our "client frame" for reading FORMs ILBM in an IFF file.
  152.  * We allocate one of these on the stack for every LIST or FORM encountered
  153.  * in the file and use it to hold BMHD & CMAP properties. We also allocate
  154.  * an initial one for the whole file.
  155.  * We allocate a new GroupContext (and initialize it by OpenRIFF or
  156.  * OpenRGroup) for every group (FORM, CAT, LIST, or PROP) encountered. It's
  157.  * just a context for reading (nested) chunks.
  158.  *
  159.  * If we were to scan the entire example file outlined below:
  160.  *    reading          proc(s)                new               new
  161.  *
  162.  * --whole file--   ReadPicture+ReadIFF   GroupContext        ILBMFrame
  163.  * CAT              ReadICat                GroupContext
  164.  *   LIST           GetLiILBM+ReadIList       GroupContext        ILBMFrame
  165.  *     PROP ILBM    GetPrILBM                   GroupContext
  166.  *       CMAP       GetCMAP
  167.  *       BMHD       GetBMHD
  168.  *     FORM ILBM    GetFoILBM                   GroupContext        ILBMFrame
  169.  *       BODY       GetBODY
  170.  *     FORM ILBM    GetFoILBM                   GroupContext        ILBMFrame
  171.  *       BODY       GetBODY
  172.  *   FORM ILBM      GetFoILBM                 GroupContext        ILBMFrame
  173.  */
  174. typedef struct {
  175.    ClientFrame clientFrame;
  176.    UBYTE foundBMHD;
  177.    UBYTE nColorRegs;
  178.    BitMapHeader bmHdr;
  179.    Color4 colorMap[maxColorReg];
  180.    /* If you want to read any other property chunks, e.g. GRAB or CAMG, add
  181.     * fields to this record to store them. */
  182.    } ILBMFrame;
  183.  
  184.  
  185. /* NOTE: For a simple version of this program, set Fancy to 0.
  186.  * That'll compile a program that skips all LISTs and PROPs in the input
  187.  * file. It will look in CATs for FORMs ILBM. That's suitable for most uses.
  188.  *
  189.  * For a fancy version that handles LISTs and PROPs, set Fancy to 1. */
  190.  
  191. #define Fancy  1
  192.  
  193. /* Modified by C. Scheppner */
  194. /*  iFrame    made global -  moved from ReadPicture() */
  195.  
  196. ILBMFrame   iFrame;       /* top level client frame */
  197.  
  198.  
  199. /** main() ****************************************************************/
  200. main(argc, argv)
  201.    int argc;
  202.    char **argv;
  203.    {
  204.    LONG            file;
  205.    IFFP            iffp = NO_FILE;
  206.    struct WBArg    *arg;  
  207.    char            *filename;
  208.  
  209.    fromWB = (argc==0) ? TRUE : FALSE;
  210.  
  211.    if(argc>1)                 /* Passed filename via command line  */
  212.       {
  213.       filename = argv[1];
  214.       }
  215.    else if ((argc==0)&&(WBenchMsg->sm_NumArgs > 1))
  216.       {                        /* Passed filename via  WorkBench */
  217.       arg = WBenchMsg->sm_ArgList;
  218.       arg++;
  219.       filename   = (char *)arg->wa_Name;
  220.       newLock    = (struct FileLock *)arg->wa_Lock;
  221.       startLock  = (struct FileLock *)CurrentDir(newLock);
  222.       }
  223.    else if (argc==1)           /* From CLI but no filename */
  224.       cleanexit("Usage: 'SeeILBM filename'\n");
  225.    else                        /* From WB but no filename */
  226.       cleanexit("\nClick ONCE on SeeILBM\nSHIFT and DoubleClick on Pic\n");
  227.  
  228.  
  229.  
  230.    if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0)))
  231.       cleanexit("Can't open graphics library\n");
  232.  
  233.    if(!(IntuitionBase=
  234.           (struct IntuitionBase *)OpenLibrary("intuition.library",0)))
  235.       cleanexit("Can't open graphics library\n");
  236.  
  237.    if(file = Open(filename, MODE_OLDFILE))
  238.       {
  239.       printf("\nCLICK PIC TOP LEFT TO END DISPLAY\n");
  240.       printf("CLICK LOWER TO TOGGLE DRAG BAR\n");
  241.       Delay(150);  /* wait about 3 seconds to give person time to read it */
  242.  
  243.       iffp = ReadPicture(file);
  244.       Close(file);
  245.       if (iffp == IFF_DONE)
  246.          {
  247.          error = DisplayPic(&iFrame);
  248.          if(error)  cleanexit("Can't open screen or window\n");
  249.  
  250.          TBtoggle   = FALSE;      /* Title bar toggle */
  251.          Done       = FALSE;      /* Close flag       */
  252.          while (!Done)
  253.             {
  254.             Wait(1<<window1->UserPort->mp_SigBit);
  255.             chkmsg();
  256.             }
  257.          }
  258.       else cleanexit(IFFPMessages[-iffp]);
  259.       }
  260.    else cleanexit("Picture file not found.\n");
  261.  
  262.    cleanup();
  263.    }
  264.  
  265.  
  266. chkmsg()
  267.    {
  268.    while(message=(struct IntuiMessage *)GetMsg(window1->UserPort))
  269.       {
  270.       class = message->Class;
  271.       code  = message->Code;
  272.       mouseX = message->MouseX;
  273.       mouseY = message->MouseY;
  274.  
  275.       ReplyMsg(message);
  276.       switch(class)
  277.          {
  278.          case MOUSEBUTTONS:
  279.             if ((code == SELECTDOWN)&&
  280.                   (mouseX < 10)&&(mouseY<10))
  281.                {
  282.                Done = TRUE;
  283.                }
  284.             else if ((code == SELECTDOWN)&&
  285.                        (mouseY>10)&&(TBtoggle==FALSE))
  286.                {
  287.                TBtoggle = TRUE;
  288.                ShowTitle(screen1,TRUE);
  289.                }
  290.             else if ((code == SELECTDOWN)&&
  291.                        (mouseY>10)&&(TBtoggle==TRUE))
  292.                {
  293.                TBtoggle = FALSE;
  294.                ShowTitle(screen1,FALSE);
  295.                }
  296.             break;
  297.          default:
  298.             printf("Unknown IDCMP message\n");
  299.          }
  300.       }
  301.    }
  302.  
  303.  
  304. cleanexit(errstr)
  305.    char  *errstr;
  306.    {
  307.    printf("\n %s \n",errstr);
  308.    cleanup();
  309.    if (fromWB)    /* Wait so user can read messages */
  310.       {
  311.       printf("\nPRESS RETURN TO CLOSE THIS WINDOW\n");
  312.       while ((c=getchar()) != '\n');
  313.       }
  314.    exit();
  315.    }
  316.  
  317. cleanup()
  318.    {
  319.    /* tBitMap planes were deallocated in DisplayPic() */
  320.    if (window1)
  321.       {
  322.       while(message=(struct IntuiMessage *)GetMsg(window1->UserPort))
  323.          {
  324.          ReplyMsg(message);
  325.          }
  326.       CloseWindow(window1);
  327.       }
  328.    if (screen1) CloseScreen(screen1);
  329.    if (IntuitionBase) CloseLibrary(IntuitionBase);
  330.    if (GfxBase)       CloseLibrary(GfxBase);
  331.    if (newLock != startLock)  CurrentDir(startLock);
  332.    }
  333.  
  334.  
  335. /** getBitMap() *********************************************************
  336.  *
  337.  * Open screen or temp bitmap.
  338.  *   Returns ptr destBitMap  or  0 = error
  339.  *
  340.  *************************************************************************/
  341. struct BitMap *getBitMap(ptilbmFrame)
  342.    ILBMFrame *ptilbmFrame;
  343.    {
  344.    int     i, nPlanes, plsize;
  345.    SHORT  sWidth, sHeight, dWidth, dHeight;
  346.    struct BitMap *destBitMap;
  347.  
  348.    sWidth  = ptilbmFrame->bmHdr.w;
  349.    sHeight = ptilbmFrame->bmHdr.h;
  350.    dWidth  = ptilbmFrame->bmHdr.pageWidth;
  351.    dHeight = ptilbmFrame->bmHdr.pageHeight;
  352.    nPlanes = MIN(ptilbmFrame->bmHdr.nPlanes, EXDepth);
  353.  
  354.    for (i = 0; i < ptilbmFrame->nColorRegs; i++)
  355.       {
  356.       allBgColor[i] = ptilbmFrame->colorMap[0];
  357.       }
  358.  
  359.    ns.Width  = dWidth;
  360.    ns.Height = dHeight;
  361.    ns.Depth  = nPlanes;
  362.  
  363.    if (ptilbmFrame->bmHdr.pageWidth <= 320)
  364.       ns.ViewModes = 0;
  365.    else
  366.       ns.ViewModes = HIRES;
  367.  
  368.    if (ptilbmFrame->bmHdr.pageHeight > 200)
  369.       ns.ViewModes |= LACE;
  370.  
  371.    if ((screen1 = (struct Screen *)OpenScreen(&ns))==NULL)    return(0);
  372.  
  373.    vport1 = &screen1->ViewPort;
  374.    LoadRGB4(vport1, &allBgColor[0], ptilbmFrame->nColorRegs);
  375.  
  376.    nw.Width  = dWidth;
  377.    nw.Height = dHeight;
  378.    nw.Screen = screen1;
  379.  
  380.    if ((window1 = (struct Window *)OpenWindow(&nw))==NULL)    return(0);
  381.  
  382.    ShowTitle(screen1, FALSE);
  383.  
  384.    if ((sWidth == dWidth) && (sHeight == dHeight))
  385.       {
  386.       destBitMap = (struct BitMap *)screen1->RastPort.BitMap;
  387.       }
  388.    else
  389.       {
  390.       InitBitMap( &tBitMap,
  391.                   nPlanes,
  392.                   sWidth,
  393.                   sHeight);
  394.  
  395.       plsize = RowBytes(ptilbmFrame->bmHdr.w) * ptilbmFrame->bmHdr.h;
  396.       if (tBitMap.Planes[0] =
  397.        (PLANEPTR)AllocMem(nPlanes * plsize, MEMF_CHIP))
  398.          {
  399.          for (i = 1; i < nPlanes; i++)
  400.             tBitMap.Planes[i] = (PLANEPTR)tBitMap.Planes[0] + plsize*i;
  401.          destBitMap = &tBitMap;
  402.          }
  403.       else
  404.          {
  405.          return(0);  /* can't allocate temp BitMap */
  406.          }
  407.       }
  408.    return(destBitMap);          /* destBitMap allocated */
  409.    }
  410.  
  411.  
  412. /** DisplayPic() *********************************************************
  413.  *
  414.  * Display loaded bitmap.  If tBitMap, first transfer to screen.
  415.  *
  416.  *************************************************************************/
  417. DisplayPic(ptilbmFrame)
  418.    ILBMFrame *ptilbmFrame;
  419.    {
  420.    int    i, row, byte, nrows, nbytes;
  421.    struct BitMap  *tbp, *sbp; /* temp and screen BitMap ptrs */
  422.    UBYTE  *tpp, *spp;         /* temp and screen plane ptrs  */
  423.  
  424.    if (tBitMap.Planes[0])     /* transfer from tBitMap if nec. */
  425.       {
  426.       tbp = &tBitMap;
  427.       sbp = screen1->RastPort.BitMap;
  428.       nrows  = MIN(tbp->Rows, sbp->Rows);
  429.       nbytes = MIN(tbp->BytesPerRow, sbp->BytesPerRow);
  430.  
  431.       for (i = 0; i < sbp->Depth; i++)
  432.          {
  433.          tpp = (UBYTE *)tbp->Planes[i];
  434.          spp = (UBYTE *)sbp->Planes[i];
  435.          for (row = 0; row < nrows; row++)
  436.             {
  437.             tpp = tbp->Planes[i] + (row * tbp->BytesPerRow);
  438.             spp = sbp->Planes[i] + (row * sbp->BytesPerRow);
  439.             for (byte = 0; byte < nbytes; byte++)
  440.                {
  441.                *spp++ = *tpp++;
  442.                }
  443.             }
  444.          }
  445.       /*  Can now deallocate the temp BitMap  */
  446.       FreeMem(tBitMap.Planes[0],
  447.                  tBitMap.BytesPerRow * tBitMap.Rows * tBitMap.Depth);
  448.       }
  449.  
  450.    vport1 = &screen1->ViewPort;
  451.    LoadRGB4(vport1, ptilbmFrame->colorMap, ptilbmFrame->nColorRegs);
  452.  
  453.    return(0);
  454.    }
  455.  
  456.  
  457. /** GetLiILBM() **********************************************************
  458.  *
  459.  * Called via ReadPicture to handle every LIST encountered in an IFF file.
  460.  *
  461.  *************************************************************************/
  462. #if Fancy
  463. IFFP GetLiILBM(parent)
  464. GroupContext *parent; {
  465.     ILBMFrame newFrame;   /* allocate a new Frame */
  466.  
  467.     newFrame = *(ILBMFrame *)parent->clientFrame;  /* copy parent frame */
  468.  
  469.     return( ReadIList(parent, (ClientFrame *)&newFrame) );
  470.     }
  471. #endif
  472.  
  473.  
  474. /** GetPrILBM() **********************************************************
  475.  *
  476.  * Called via ReadPicture to handle every PROP encountered in an IFF file.
  477.  * Reads PROPs ILBM and skips all others.
  478.  *
  479.  *************************************************************************/
  480. #if Fancy
  481. IFFP GetPrILBM(parent)
  482. GroupContext *parent; {
  483.    /*compilerBug register*/ IFFP iffp;
  484.    GroupContext propContext;
  485.    ILBMFrame *ilbmFrame = (ILBMFrame *)parent->clientFrame;
  486.  
  487.    if (parent->subtype != ID_ILBM)
  488.       return(IFF_OKAY);   /* just continue scaning the file */
  489.  
  490.    iffp = OpenRGroup(parent, &propContext);
  491.    CheckIFFP();
  492.  
  493.    do switch (iffp = GetPChunkHdr(&propContext)) {
  494.       case ID_BMHD: {
  495.          ilbmFrame->foundBMHD = TRUE;
  496.          iffp = GetBMHD(&propContext, &ilbmFrame->bmHdr);
  497.          break; }
  498.       case ID_CMAP: {
  499.          ilbmFrame->nColorRegs = maxColorReg; /* room for this many */
  500.          iffp = GetCMAP( &propContext, (WORD *)ilbmFrame->colorMap,
  501.                           &ilbmFrame->nColorRegs);
  502.          break; }
  503.  
  504.       } while (iffp >= IFF_OKAY);/* loop if valid ID of ignored chunk or
  505.                                   * subrtn returned IFF_OKAY (no errors).*/
  506.  
  507.    CloseRGroup(&propContext);
  508.    return(iffp == END_MARK ? IFF_OKAY : iffp);
  509.    }
  510. #endif
  511.  
  512.  
  513. /** GetFoILBM() **********************************************************
  514.  *
  515.  * Called via ReadPicture to handle every FORM encountered in an IFF file.
  516.  * Reads FORMs ILBM and skips all others.
  517.  * Inside a FORM ILBM, it stops once it reads a BODY. It complains if it
  518.  * finds no BODY or if it has no BMHD to decode the BODY.
  519.  *
  520.  * Once we find a BODY chunk, we'll allocate the BitMap and read the image.
  521.  *
  522.  *
  523.  *************************************************************************/
  524. IFFP GetFoILBM(parent)
  525.    GroupContext *parent;
  526.    {
  527.    IFFP iffp;
  528.    GroupContext formContext;
  529.    ILBMFrame    ilbmFrame;
  530.    BYTE buffer[bufSz];
  531.    struct BitMap *destBitMap;
  532.  
  533.    if (parent->subtype != ID_ILBM)
  534.       return(IFF_OKAY);   /* just continue scaning the file */
  535.  
  536.    ilbmFrame = *(ILBMFrame *)parent->clientFrame;
  537.    iffp = OpenRGroup(parent, &formContext);
  538.    CheckIFFP();
  539.  
  540.    do switch (iffp = GetFChunkHdr(&formContext)) {
  541.       case ID_BMHD: {
  542.          ilbmFrame.foundBMHD = TRUE;
  543.          iffp = GetBMHD(&formContext, &ilbmFrame.bmHdr);
  544.          break; }
  545.       case ID_CMAP: {
  546.          ilbmFrame.nColorRegs = maxColorReg;  /* we have room for this many */
  547.          iffp = GetCMAP(&formContext, (WORD *)ilbmFrame.colorMap,
  548.                            &ilbmFrame.nColorRegs);
  549.          break; }
  550.       case ID_BODY: {
  551.          if (!ilbmFrame.foundBMHD)
  552.             {
  553.             iffp = BAD_FORM;   /* No BMHD chunk! */
  554.             }
  555.          else
  556.             {
  557.             if(destBitMap=(struct BitMap *)getBitMap(&ilbmFrame))
  558.                {
  559.                iffp = GetBODY( &formContext,
  560.                                destBitMap,
  561.                                NULL,
  562.                                &ilbmFrame.bmHdr,
  563.                                buffer,
  564.                                bufSz);
  565.                if (iffp == IFF_OKAY) iffp = IFF_DONE;   /* Eureka */
  566.                }
  567.             else
  568.                {
  569.                iffp = CLIENT_ERROR;   /* not enough RAM for the bitmap */
  570.                }
  571.             }
  572.          break; }
  573.  
  574.       case END_MARK: {
  575.          iffp = BAD_FORM;
  576.          break; }
  577.  
  578.    } while (iffp >= IFF_OKAY);  /* loop if valid ID of ignored chunk or a
  579.            * subroutine returned IFF_OKAY (no errors).*/
  580.  
  581.    iFrame = ilbmFrame;
  582.  
  583.    if (iffp != IFF_DONE)  return(iffp);
  584.  
  585.    CloseRGroup(&formContext);
  586.    return(iffp);
  587.    }
  588.  
  589. /** Notes on extending GetFoILBM *****************************************
  590.  *
  591.  * To read more kinds of chunks, just add clauses to the switch statement.
  592.  * To read more kinds of property chunks (GRAB, CAMG, etc.) add clauses to
  593.  * the switch statement in GetPrILBM, too.
  594.  *
  595.  * To read a FORM type that contains a variable number of data chunks--e.g.
  596.  * a FORM FTXT with any number of CHRS chunks--replace the ID_BODY case with
  597.  * an ID_CHRS case that doesn't set iffp = IFF_DONE, and make the END_MARK
  598.  * case do whatever cleanup you need.
  599.  *
  600.  *************************************************************************/
  601.  
  602.  
  603. /** ReadPicture() ********************************************************
  604.  *
  605.  * Read a picture from an IFF file, given a file handle open for reading.
  606.  *
  607.  * Modified by Carolyn Scheppner   CBM   03-86
  608.  *   iFrame made global (above main)
  609.  *   Close(file) moved to main
  610.  *
  611.  *************************************************************************/
  612. IFFP ReadPicture(file)
  613.       LONG file;
  614.    {
  615.    IFFP iffp = IFF_OKAY;
  616.  
  617. #if Fancy
  618.    iFrame.clientFrame.getList = GetLiILBM;
  619.    iFrame.clientFrame.getProp = GetPrILBM;
  620. #else
  621.    iFrame.clientFrame.getList = SkipGroup;
  622.    iFrame.clientFrame.getProp = SkipGroup;
  623. #endif
  624.    iFrame.clientFrame.getForm = GetFoILBM;
  625.    iFrame.clientFrame.getCat  = ReadICat ;
  626.  
  627.    /* Initialize the top-level client frame's property settings to the
  628.     * program-wide defaults. This example just records that we haven't read
  629.     * any BMHD property or CMAP color registers yet. For the color map, that
  630.     * means the default is to leave the machine's color registers alone.
  631.     * If you want to read a property like GRAB, init it here to (0, 0). */
  632.    iFrame.foundBMHD  = FALSE;
  633.    iFrame.nColorRegs = 0;
  634.  
  635.    iffp = ReadIFF(file, (ClientFrame *)&iFrame);
  636.    return(iffp);
  637.    }
  638.  
  639.  
  640. oundBMHD